46. 日志

历史遗留问题

市场上存在非常多的日志框架。JUL(java.util.logging), JCL(Jakarta Commons Logging),Log4j, Log4j2, Logback (具体框架, springboot使用)、SLF4j、jboss-logging 等。Spring 在框架内部使用JCL。 Log4j 被 apache收购,升级,改为log4j2,框架改动很大,只是借用之名。Log4j, Logback, SLF4j都是同一个作者。

日志门面(规范) 日志实现
JCL (Jakarta Commons Logging)
SLF4j (simple Logging Facade for java)
jboss-logging
Log4j
JUL(java.util.logging)
Log4j2
Logback

springboot(slf4j+logback): Spring(commons-logging)、Hibernate(jboss-logging)、 每个框架使用的日志框架都不一样,由此我们要进行统一管理。

优先选择 slf4j + logback 或者 slf4j + log4j 的方案。如下图中的第二部分和第三部分。

解决方法

方案1:采用 SLF4J + logback 的方式【SLF4J 门面,Logback 是具体实现】 (SpringBoot 底层就是这么实现的,所以优选这个方案)

方案2:采用 SLF4J + log4j 的方式【SLF4J 门面,log4j 是具体实现】

替换代码中的 commons-logging 和 jul

查询所有 pom 文件中的依赖,将 commons-logging 进行排除,然后在 parent 父模块的 pom 中引入 jcl-over-slf4j 进行替换。引入 jul-to-slf4j 进行替换 jul(因为 jul 是 java 自身实现的,所有无法像 commons-logging 一样进行排除)

在 parent 中添加 jcl-over-slf4j 和 jul-to-slf4j

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<properties>
<jcl.over.slf4j.version>1.7.25</jcl.over.slf4j.version>
<jul-to-slf4j.version>1.7.25</jul-to-slf4j.version>
</properties>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId><!-- 替换commons-logging-->
<version>${jcl.over.slf4j.version}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId><!-- 替换java.util.logging-->
<version>${jul-to-slf4j.version}</version>
</dependency>

并在 common 模块的 pom 文件中进行依赖的引入,这样所有直接或者间接依赖 common 的项目都有 jcl-over-slf4j 和 jul-to-slf4j 了。

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId><!-- 替换commons-logging-->
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId><!-- 替换java.util.logging-->
</dependency>

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.atguigu.test;

import static org.junit.Assert.*;

import org.junit.Test;
import org.slf4j.Logger; // 注意使用的是 slf4j 中的
import org.slf4j.LoggerFactory; // 注意使用的是 slf4j 中的


public class Slf4jTest {

public static void main(String[] args) {
Logger log = LoggerFactory.getLogger(Slf4jTest.class);
log.debug("debug message: id = {}, name = {}", 1, "zhangsan");
log.info("info message: id = {}, name = {}", 2, "lisi");
log.warn("warn message: id = {}, name = {}", 2, "lisi");
log.error("error message: id = {}, name = {}", 2, "lisi");
}
}

logback.xml

每一个日志的实现框架都有自己的配置文件。使用slf4j以后,配置文件还是做成日志实现框架自己本身的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 指定日志输出的地方, 这里是 Console-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<!-- 日志:从低到高;只会打印指定级别以后的; additivity表示是否将日志信息反馈给root
DEBUG==》INFO===》WARN===》ERROR
<logger name="com.atguigu.atcrowdfunding.mapper" level="debug" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
  -->
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>